The present disclosure relates to functional verification of a processor hardware design in general, and to test generation of stimuli operative to stimulate the design to perform speculative execution, in particular.
Computerized devices control almost every aspect of our life—from writing documents to controlling traffic lights. However, computerized devices are bug-prone, and thus require a testing phase in which the bugs should be discovered. The testing phase is considered one of the most difficult tasks in designing a computerized device. The cost of not discovering a bug may be enormous, as the consequences of the bug may be disastrous. For example, a bug may cause the injury of a person relying on the designated behavior of the computerized device. Additionally, a bug in hardware or firmware may be expensive to fix, as patching it requires call-back of the computerized device. Hence, many developers of computerized devices invest a substantial portion of the development cycle to discover erroneous behaviors of the computerized device.
Hardware-based speculation increases the parallel execution of instructions by speculating on the outcome of conditional branch instructions and executing the instruction stream as if the speculated guess is correct. With speculation the processor fetches, issues and executes instructions, but the results of the execution are not written back into architected resources until the speculation is resolved. This may be done by separating the completion stage from the commit stage. Results from completed instructions are forwarded into other instructions to allow their speculative execution.
In hardware-based speculation, in instruction after which the control may flow into two or more different locations, speculative execution may be used. Such an instruction is referred to as a branch instruction. A branch instruction may define two or more branch legs. The branch instruction may be conditional and define a condition which defines which of the branch legs is to be taken. For example, the branch instruction may define that if a condition is held, a first branch leg is taken, and if the condition is not held, a second branch leg is taken. During execution, the taken branch leg is executed. However, the non-taken branch leg (also referred to as the Branch-leg Not Taken, or BNT) may also be executed in speculative execution, whose results may be dropped later on. In some exemplary embodiments, the taken branch leg may be executed speculatively, and those results may be used later on.
Once the speculation is resolved, in case the speculation was correct (i.e., the taken branch leg was executed speculatively), all the instructions which executed speculatively are allowed to commit—i.e. write their results into architected resources in program order. In case the speculation was wrong (i.e., the BNT was executed speculatively), the speculative execution is revoked by performing a rollback operation. The rollback operation may require performing a complex chain of undo operations within the processor.
Implementing a speculative execution mechanism considerably complicates processor design. It requires the addition of a set of hardware buffers that hold the results of instructions that finished executing but have not yet committed, and also requires the ability to pass results among speculatively executing instructions. Hence, hardware-based speculation is somewhat bug-prone, and its verification is an important task.
Functional verification of processor designs is based largely on test generation techniques. These techniques generate stimuli in the form of machine-language programs. Faulty behavior of the design is detected by driving the stimuli into a design simulator and comparing the actual behavior of the design with the expected behavior implied by the input stimuli. However, in some cases, another test platform may be used instead of a simulator, such as a hardware emulator, a hardware accelerator, a post-silicon product (e.g., a prototype or a wafer), or the like.
Test generators may be generally classified into two distinct groups. Layout generators are configured to generate a test based on a template which describes the layout of the test. In other words, the layout of instructions in the template is the layout of instructions of the generated test as well. Flow generators are configured to generate a test based on a template which describes the order of execution. Hence, in a flow generator, an order of instructions in the template defines an order of execution in the test, and not necessarily the layout of the test.
The two different generators are noticeably different with respect to branching instructions. In a layout generator, the instruction succeeding a branch instruction in the template is placed in memory right after the branch instruction. In a flow generator, the placement of the instruction succeeding the branch depends on whether the branch is taken or not taken. If the branch is not taken, the succeeding instruction in the template is placed right after the branch instruction, however if the branch is taken, the succeeding instruction is placed at the target address of the branch instruction, and the placement continuity is broken.
Dynamic generators utilize a reference model to simulate an expected state of the target design during the generation of the test, and therefore are able to provide for tests of higher quality as such a dynamic generator may generate more interesting stimuli based on a current expected state of the design. Dynamic generation is disclosed in U.S. Pat. No. 5,202,889 titled “Dynamic Process for the generation of biased pseudo-random test patterns for the functional verification of hardware designs”, which is hereby incorporated by reference. In dynamic generation the generator generates an instruction, executes the generated instruction on a reference model to calculate the new machine state, and generates the next instruction based on the updated state. In some exemplary embodiments, flow generators are dynamic generators.